package com.spring.framework.ioc.xml;

import com.spring.framework.model.learn.ReflectWarning;
import com.spring.framework.model.xml.Book;
import com.spring.framework.model.xml.InnerBean;
import com.spring.framework.model.xml.SpringBean;
import com.spring.framework.model.xml.inject.*;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

/**
 * @author xuweizhi
 * @since 2020/12/08 15:37
 */
public class SpringBeanTest extends ReflectWarning {

	@Test
	public void testInnerClass() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-config.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
		SpringBean factorSpringBean = (SpringBean) ac.getBean("factorySpringBean");
		System.out.println(factorSpringBean);
	}

	@Test
	public void testStaticFactory() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-factory.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
		SpringBean factorSpringBean = (SpringBean) ac.getBean("springBean");
		System.out.println(factorSpringBean);
	}

	@Test
	public void testConstructor() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-dependency-inject.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
		Book book = (Book) ac.getBean("book");
		System.out.println(book);
	}

	@Test
	public void innerBean() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-inner-bean.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
		InnerBean innerBean = ac.getBean("innerBean", InnerBean.class);
		System.out.println(innerBean);
	}

	@Test
	public void collectionInject() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-collections.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
		System.out.println(ac.getBean("collectionInject", CollectionInject.class));
	}

	@Test
	public void testLazy() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-lazy.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
	}

	@Test
	public void autowire() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-autowire.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
		System.out.println(ac.getBean("autowireInjectA0", AutowireInject.AutowireInjectA.class));
		System.out.println(ac.getBean("autowireInjectA1", AutowireInject.AutowireInjectA.class));
		System.out.println(ac.getBean("autowireInjectA2", AutowireInject.AutowireInjectA.class));
		System.out.println(ac.getBean("autowireInjectA3", AutowireInject.AutowireInjectA.class));
	}

	@Test
	public void lookupMethod() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-lookup.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
		LookupMethodInject.LookupMethodInjectA lookupMethodInjectA = ac.getBean("lookupMethodInjectA", LookupMethodInject.LookupMethodInjectA.class);
		System.out.println("获取lookupMethodInjectB，同一个对象");
		System.out.println("lookupMethodInjectB：" + lookupMethodInjectA.getLookupMethodInjectB());
		System.out.println("lookupMethodInjectB：" + lookupMethodInjectA.getLookupMethodInjectB());
		System.out.println("lookupMethodInjectB：" + lookupMethodInjectA.getLookupMethodInjectB());
		System.out.println("获取lookupMethodInjectC，不同的对象");
		System.out.println("lookupMethodInjectC：" + lookupMethodInjectA.getLookupMethodInjectC());
		System.out.println("lookupMethodInjectC：" + lookupMethodInjectA.getLookupMethodInjectC());
		System.out.println("lookupMethodInjectC：" + lookupMethodInjectA.getLookupMethodInjectC());

		//实际上lookupMethodInjectA的lookupMethodInjectC属性根本没有被注入过，每一次的getLookupMethodInjectC都是直接找容器要对象
		//而由于lookupMethodInjectC被设置为prototype，因此每一次都会获取新的对象
		System.out.println("lookupMethodInjectA：" + lookupMethodInjectA);
	}

	@Test
	public void arbitraryMethodRe() {
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-method-replace.xml");
		System.out.println(Arrays.toString(ac.getBeanDefinitionNames()));
		ArbitraryMethodRe.TimeConverter timeConverter = ac.getBean("timeConverter", ArbitraryMethodRe.TimeConverter.class);
		System.out.println(timeConverter.convert((byte) 3));
	}

	@Test
	public void lifecycleCallback() {
		//开启容器
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("config/ioc/spring-lifecycle.xml");
		//主动获取bean才会回调
		ac.getBean("lifecycleCallbackPro", LifecycleCallback.LifecycleCallbackPro.class);
		ac.getBean("lifecycleCallbackPro", LifecycleCallback.LifecycleCallbackPro.class);
		//close关闭容器，一定是close才会触发
		ac.close();
		//gc不一定发生，对象不一定被彻底销毁
		System.gc();
	}

}
